package main

import (
	"fmt"
	"time"
)

// 结构体
// Golang 中 通过 struct 实现面向对象
// 结构体 是 值类型

type Person struct {
	Age    int
	Name   string
	Gender string
	Hobby  []string
}

// golang 中 函数参数都是副本
func change(p Person) {
	// 修改 的是 副本的 Gender
	p.Gender = "女"
}

func change2(p *Person) {
	// 根据内存地址 找到 原变量 并修改
	// (*p).Gender = "女"

	// 语法糖 自动根据指针找到变量
	p.Gender = "女"
}

func main() {
	// 声明一个 person 类型的变量
	var p1 Person
	// 通过字段赋值
	p1.Name = "于谦"
	p1.Age = time.Now().Year() - 1969
	p1.Gender = "男"
	p1.Hobby = []string{"抽烟", "喝酒", "烫头"}
	// 访问 Name 字段
	fmt.Println(p1.Name)
	fmt.Printf("type: %T value: %#v\n", p1, p1)

	// 匿名结构体 一般用于临时场景
	var s struct {
		name string
		age  int
	}

	s.name = "s"
	s.age = 100
	fmt.Printf("type: %T value: %#v\n", s, s)

	fmt.Println("=========================================================")

	change(p1)
	fmt.Printf("type: %T value: %#v\n", p1, p1)

	change2(&p1)
	fmt.Printf("type: %T value: %#v\n", p1, p1)

	fmt.Println("=========================================================")

	var p2 = new(Person)
	(*p2).Name = "person2"
	p2.Age = 10086
	fmt.Printf("type: %T value: %#v\n", p2, p2)
	fmt.Printf("内存地址: %p\n", p2)
	fmt.Printf("p2 的 内存地址: %p\n", &p2)

	fmt.Println("=========================================================")

	// 声明并初始化 结构体
	var p3 = Person{Name: "张三", Gender: "男"}
	fmt.Printf("type: %T value: %#v\n", p3, p3)

	// 使用值列表的形式初始化 结构体
	// 值的 顺序 要和 结构体定义的 字段顺序 一致
	var p4 = Person{20, "李四", "男", []string{}}
	fmt.Printf("type: %T value: %#v\n", p4, p4)

	fmt.Println("=========================================================")
	// 声明并初始化 结构体 指针 (常用)
	var p5 = &Person{Name: "王五", Gender: "男"}
	fmt.Printf("type: %T value: %#v\n", p5, p5)

	// 使用值列表的形式初始化 结构体指针
	// 值的 顺序 要和 结构体定义的 字段顺序 一致
	var p6 = &Person{20, "赵六", "男", []string{}}
	fmt.Printf("type: %T value: %#v\n", p6, p6)
}
